package com.xcity.util;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import naga.x.App;
import naga.x.db.DBSession;
import naga.x.db.IMapper;

public class DBUtils {

	private static final ThreadLocal<DBSession> SESSIONS = new ThreadLocal<DBSession>();
	
	public interface MapperInvoker<E, M extends IMapper<E>> {
		<T> T invoke(M mapper);
	}
	
	public static DBSession getSession() {
		DBSession sess = SESSIONS.get();
		if (sess == null) {
			sess = App.getApp().getDBSessionFactory().getSession();
			SESSIONS.set(sess);
		}
		return sess;
	}
	
	public static <M extends IMapper<?>> M getMapper(Class<M> mapperClass) {
		DBSession sess = getSession();
		return sess.getMapper(mapperClass);
	}
	
	public static void close() {
		DBSession sess = SESSIONS.get();
		if (sess != null) {
			SESSIONS.remove();
			try {
				sess.commit();
			} catch (Exception e) {
				sess.rollback();
				e.printStackTrace();
			} finally {
				sess.close();
			}
		}
	}
	
	public static <E, M extends IMapper<E>> E find(Serializable id, Class<M> mapperType) {
		try {
			M mapper = getMapper(mapperType);
			return mapper.find(id);
		} finally {
			close();
		}
	}
	
	public static <E, M extends IMapper<E>> List<E> findAll(Class<M> mapperType) {
		try {
			M mapper = getMapper(mapperType);
			return mapper.findAll();
		} finally {
			close();
		}
	}
	
	public static <E, M extends IMapper<E>> List<E> findLimit(Class<M> mapperType, int offset, int count, Map<String, ?> params) {
		try {
			M mapper = getMapper(mapperType);
			return mapper.findLimit(offset, count, params);
		} finally {
			close();
		}
	}
	
	public static <E, M extends IMapper<E>> void save(E entity, Class<M> mapperType) {
		try {
			M mapper = getMapper(mapperType);
			mapper.save(entity);
		} finally {
			close();
		}
	}
	
	public static <E, M extends IMapper<E>> void batchSave(Class<M> mapperType, Collection<E> entities) {
		try {
			M mapper = getMapper(mapperType);
			for (E e : entities) {
				mapper.save(e);
			}
		} finally {
			close();
		}
	}
	
	public static <E, M extends IMapper<E>> void update(E entity, Class<M> mapperType) {
		try {
			M mapper = getMapper(mapperType);
			mapper.update(entity);
		} finally {
			close();
		}
	}
	
	public static <E, M extends IMapper<E>> void batchUpdate(Class<M> mapperType, Collection<E> entities) {
		try {
			M mapper = getMapper(mapperType);
			for (E e : entities) {
				mapper.update(e);
			}
		} finally {
			close();
		}
	}
	
//	public static <E, M extends IMapper<E>> void saveOrUpdate(E entity, Class<M> mapperType) {
////		try {
////			M mapper = getMapper(mapperType);
////			if (mapper.find((Serializable) entity) != null) {
////				mapper.update(entity);
////			} else {
////				mapper.save(entity);
////			}
////		} finally {
////			close();
////		}
//	}
	
	public static <E, M extends IMapper<E>> void delete(Serializable id, Class<M> mapperType) {
		try {
			M mapper = getMapper(mapperType);
			mapper.delete(id);
		} finally {
			close();
		}
	}
	
	public static <E, M extends IMapper<E>, T> T invoke(Class<M> mapperType, MapperInvoker<E, M> invoker) {
		try {
			M mapper = getMapper(mapperType);
			return invoker.invoke(mapper);
		} finally {
			close();
		}
	}
	
	public static <E> E select(String statement, Object parameter) {
		List<E> list = selectList(statement, parameter);
		return list.size() > 0 ? list.get(0) : null;
	}
	
	public static <E> List<E> selectList(String statement, Object parameter) {
		try {
			return getSession().selectList(statement, parameter);
		} finally {
			close();
		}
	}
	
	public static int insert(String statement) {
		return insert(statement, null);
	}

	public static int insert(String statement, Object parameter) {
		try {
			return getSession().insert(statement, parameter);
		} finally {
			close();
		}
	}
	
	public static int update(String statement) {
		try {
			return getSession().update(statement, null);
		} finally {
			close();
		}
	}
	
	public static int update(String statement, Object parameter) {
		try {
			return getSession().update(statement, parameter);
		} finally {
			close();
		}
	}
	
	public static int delete(String statement) {
		try {
			return getSession().delete(statement, null);
		} finally {
			close();
		}
	}

	public static int delete(String statement, Object parameter) {
		try {
			return getSession().delete(statement, parameter);
		} finally {
			close();
		}
	}
	
	public static Map<String, Object> wrapParams(Object... keysAndParams) {
		int len = keysAndParams.length;
		Map<String, Object> map = new HashMap<String, Object>(len >> 1);
		for (int i = 0; i < len; i += 2) {
			if (i + 1 >= len) {
				break;
			}
			String key = String.valueOf(keysAndParams[i]);
			Object val = keysAndParams[i + 1];
			map.put(key, val);
		}
		return map;
	}
	
}
